import random
from django import forms
from web.models import UserInfo
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from django.conf import settings
from utils.tencent.sms import send_sms_single
from django_redis import get_redis_connection
from utils import encrypt
from .boot_strap import BootStrap

class RegisterModelForm(BootStrap,forms.ModelForm):
    # 可以在次进行重写form中的字段
    # 添加确认密码，验证码等字段
    password = forms.CharField(label="密码",
                               min_length=8,
                               max_length=64,
                               error_messages={
                                   "min_length": "密码长度不能小于8个字符",
                                   "max_length": "密码长度不能大于64个字符",
                               },
                               widget=forms.PasswordInput())
    confirm_password = forms.CharField(label="确认密码",
                                       min_length=8,
                                       max_length=64,
                                       error_messages={
                                           "min_length": "确认密码长度不能小于8个字符",
                                           "max_length": "确认密码长度不能大于64个字符",
                                       },
                                       widget=forms.PasswordInput())
    code = forms.CharField(label="验证码", widget=forms.TextInput())
    mobile_phone = forms.CharField(label="手机号", validators=[RegexValidator(r"1[3|4|5|6|7|8|9]\d{9}$", "手机号格式错误"), ])

    class Meta:
        model = UserInfo
        fields = ["username", "email", "password", "confirm_password", "mobile_phone", "code"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs["class"] = "form-control"
            field.widget.attrs["placeholder"] = "请输入%s" % field.label


    # 对注册的数据进行校验，写钩子函数，分别对每个字段进行校验

    def clean_username(self):
        """校验用户名不能重复"""
        user_name = self.cleaned_data.get("username")
        exists = UserInfo.objects.filter(username=user_name).exists()
        if exists:
            raise ValidationError("用户名已存在")
        return user_name

    def clean_email(self):
        """校验邮箱不能重复"""
        email = self.cleaned_data.get("email")
        exists = UserInfo.objects.filter(email=email).exists()
        if exists:
            raise ValidationError("邮箱已存在")
        return email
    def clean_password(self):
        """对密码进行加密操作，加密&返回"""
        password = self.cleaned_data.get("password")
        print(encrypt.md5(password))
        return encrypt.md5(password)

    def clean_confirm_password(self):
        """校验两次密码是否一致"""
        password = self.cleaned_data.get("password")
        confirm_password = encrypt.md5(self.cleaned_data.get("confirm_password"))
        print("confirm_password",confirm_password)
        if password != confirm_password:
            raise ValidationError("两次密码不一致")
        return confirm_password

    # def clean_mobile_phone(self):
    #     """校验手机号是否已经注册（重复）"""
    #     mobile_phone = self.cleaned_data.get("mobile_phone")
    #     exists = UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
    #     if exists:
    #         raise ValidationError("手机号已经注册")

    def clean_code(self):
        code = self.cleaned_data.get("code")
        mobile_phone = self.cleaned_data.get("mobile_phone")
        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)  # 是一个byte类型
        if not redis_code:
            raise ValidationError("验证码失效或未发送，请重新发送。")
        if code.strip() != redis_code.decode("utf-8"):  # 对code加上strip()，防止用户输入空格。
            raise ValidationError("验证码输入错误，请重新输入。")
        return code



### 校验手机号，发送短信
class SendSmsForm(forms.Form):
    # 用来校验手机号不能为空，且格式正确
    mobile_phone = forms.CharField(label="手机号", validators=[RegexValidator(r"1[3|4|5|6|7|8|9]\d{9}$", "手机号格式不正确")])

    # 定义一个初始化方法，将request传进来
    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request


    # 定义一个钩子函数，用来校验手机号是否存在
    def clean_mobile_phone(self):


        mobile_phone = self.cleaned_data.get("mobile_phone")
        print(mobile_phone)
        exists = UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        # 判断短信模板是否有问题
        tpl = self.request.GET.get("tpl")
        template_id = settings.SMS_TEMPLATE.get(tpl)
        print(template_id)
        if not template_id:
            raise ValidationError("短息模板错误")
        if tpl == "login":
           if not exists:
                raise ValidationError("手机号不存在")
        else:
            # 校验数据库中是否已有手机号
            if exists:
                raise ValidationError("手机号已存在")

        # 发送短信 & 写入Redis
        code = random.randrange(1000, 9999)
        # 发送短信
        sms = send_sms_single(mobile_phone, template_id, [code, ])
        # print(sms)  # {'result': 0, 'errmsg': 'OK', 'ext': '', 'sid': '8:KOmI0q0nI3RKnd3kgMs20210115', 'fee': 1, 'isocode': 'CN'}
        if sms["result"] != 0:  # 短信没有发送成功，发送成功时为0
            raise ValidationError("短信发送失败, {}".format(sms["errmsg"]))
        # 将短信验证码写入redis(django-redis组件）
        conn = get_redis_connection()
        # print(conn)  # Redis<ConnectionPool<Connection<host=192.168.74.177,port=6379,db=0>>>
        conn.set(mobile_phone, code, ex=60)
        # print(conn.get(mobile_phone))  # b'2914'
        return mobile_phone

### 用来生成短信验证登陆页面
class LoginSmsModelForm(BootStrap,forms.ModelForm):

    mobile_phone = forms.CharField(label="手机号", validators=[RegexValidator(r"1[3|4|5|6|7|8|9]\d{9}$", "手机号格式错误"), ])
    code = forms.CharField(label="验证码", widget=forms.TextInput())
    class Meta:
        model = UserInfo
        fields = ["mobile_phone", "code"]

    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data.get("mobile_phone")
        exists = UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if not exists:
            raise ValidationError("手机号不存在")
        return mobile_phone

    def clean_code(self):
        code = self.cleaned_data.get("code")
        mobile_phone = self.cleaned_data.get("mobile_phone")
        # 手机号不存在，则验证码无序再校验
        if not mobile_phone:
            return code
        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)
        if not redis_code:
            raise ValidationError("验证码失效或未发送，请重新发送")
        redis_str_code = redis_code.decode("utf-8")
        if code.strip() != redis_str_code:
            raise ValidationError("验证码错误，请重新输入")
        return code

### 用户名密码登录页
class LoginForm(BootStrap,forms.ModelForm):
    # 重写init方法，将request变量传入
    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request


    username = forms.CharField(label="邮箱或手机号")
    password = forms.CharField(label="密码", widget=forms.PasswordInput(render_value=True))
    code = forms.CharField(label="图片验证码")
    class Meta:
        model = UserInfo
        fields = ["username", "password", "code"]
    def clean_password(self):
        """对输入得密码进行加密"""
        password = self.cleaned_data.get("password")
        return encrypt.md5(password)
    def clean_code(self):
        """钩子函数，用来校验图片验证码是否正确"""
        # 读取用户输入得验证码
        code = self.cleaned_data.get("code")
        # 去session中获取自己得验证码
        session_code = self.request.session.get("image_code")
        if not session_code:
            raise ValidationError("验证码已过期，请重新获取")
        if code.strip().upper() != session_code.strip().upper():
            raise ValidationError("验证码输入错误！")


